﻿using System.Collections;
using System.Collections.Generic;
using System.IO;
using System;
namespace SGLisp
{

    public class RT
    {
        public static Context MainContext;
        public static NameSpace CoreNameSpace;
        public static Dictionary<string, NameSpace> ImportNameSpaces;
        public static List<Action<ASTNode,ASTNode>> Macros;  
        public static void InitRuntime() 
        {
            if (MainContext == null)
            {
                MainContext = CreateMainContext();
                //CoreNameSpace = new NameSpace("core");
            }
        }

        public static void DefineMacro(Action<ASTNode, ASTNode> listNode)
        {
            if (Macros == null)
            {
                Macros = new List<Action<ASTNode, ASTNode>>();
            }
            Macros.Add(listNode);
        }

        public static ASTTree LoadASTTree(string filePath)
        {
            StreamReader sr =  File.OpenText(filePath);
            string astStr = sr.ReadToEnd();
            sr.Close();
            sr.Dispose();
            ASTTree tree = ASTTree.ParseString(filePath, astStr);
            for (int i=0;i<tree.Roots.Count;i++)
            {
                ApplyMacro(tree.Roots[i],null);
            }
            return tree;
        }
        
        public static Context CreateMainContext() 
        {
            Context context = new Context();
            CoreFunction.SetCoreFunction(context);
            //CoreNameSpace.NameSpaceContext = MainContext;
            return context;
        }

        public static void EvaluateTree(ASTTree tree) 
        {
            for (int i = 0; i < tree.Roots.Count; i++)
            {
                Evaluate(tree.Roots[i],MainContext);
            }
        }
        public static void EvaluateTree(ASTTree tree, Context context) 
        {
            for (int i = 0; i < tree.Roots.Count; i++)
            {
                Evaluate(tree.Roots[i], context);
            }
        }
        public static ASTNode Evaluate(ASTNode node,Context context)
        {
            switch (node.NodeType)
            {
                case ASTNode.ASTNodeType.ListNode:
                    ListNode lstNode = node as ListNode;
                    if (lstNode.nodes.First!=null)
                    {
                        ASTNode curVar = Evaluate(lstNode.nodes.First.Value, context);
                        if (curVar.NodeType == ASTNode.ASTNodeType.FunctionNode)
                        {
                            List<ASTNode> args = new List<ASTNode>(lstNode.nodes);
                            args.RemoveAt(0);
                            return ((FunctionNode)curVar).Exec(args, context);
                        }
                        else if (curVar.NodeType == ASTNode.ASTNodeType.MapNode)
                        {

                        }
                    }
                    else
                    {
                        throw new Exception("list first element must  symbolNode");
                    }
                    break;
                case ASTNode.ASTNodeType.SymbolNode:
                    ASTNode retNode = context.Find(((SymbolNode)node).Val);
                    if (retNode == null)
                    {
                        throw new Exception("没有找到" + ((SymbolNode)node).Val + "对应的值");
                    }
                    return retNode;
                case ASTNode.ASTNodeType.MapNode:
                    MapNode mapNode = (MapNode)node;
                    Hashtable newDic = new Hashtable();
                    foreach (DictionaryEntry DicItem in mapNode.Values)
                    {
                        newDic[DicItem.Key] = Evaluate((ASTNode)DicItem.Value, context);
                    }
                    MapNode newMapNode = new MapNode();
                    newMapNode.Values = newDic;
                    return newMapNode;
                case ASTNode.ASTNodeType.VectorNode:
                    VectorNode vecNode = (VectorNode)node;
                    VectorNode retNodes = new VectorNode();
                    retNodes.nodes = new ASTNode[vecNode.nodes.Length];
                    for (int i=0;i<vecNode.nodes.Length;i++)
                    {

                        retNodes.nodes[i] = Evaluate(vecNode.nodes[i],context);
                    }
                    return retNodes;
                case ASTNode.ASTNodeType.FunctionNode:
                case ASTNode.ASTNodeType.FnLiteralNode:
                case ASTNode.ASTNodeType.NumberNode:
                case ASTNode.ASTNodeType.StringNode:
                case ASTNode.ASTNodeType.QuoteNode:
                case ASTNode.ASTNodeType.BoolNode:
                case ASTNode.ASTNodeType.ObjectNode:
                case ASTNode.ASTNodeType.NilNode:
                case ASTNode.ASTNodeType.KeywordNode:
                    return node;

            }
            return null;
        }
        public static object EvalNode(ASTNode node, Context context)
        {
            switch (node.NodeType)
            {
                case ASTNode.ASTNodeType.ListNode:
                    ListNode lstNode = (ListNode)node;
                    LinkedList<object> retLst = new LinkedList<object>();
                    foreach (ASTNode nodeElem in lstNode.nodes)
                    {
                        retLst.AddLast( EvalNode(nodeElem,context));
                    }
                    return lstNode.nodes;
                case ASTNode.ASTNodeType.MapNode:
                    MapNode mapNode = (MapNode)node;
                    Hashtable RetValue = new Hashtable();
                    foreach (DictionaryEntry DicItem in mapNode.Values)
                    {
                        RetValue.Add(EvalNode((ASTNode)DicItem.Key, context), EvalNode((ASTNode)DicItem.Value, context));
                    }
                    return RetValue;
                case ASTNode.ASTNodeType.QuoteNode:
                case ASTNode.ASTNodeType.FunctionNode:
                    return node;
                case ASTNode.ASTNodeType.BoolNode:
                    return ((BoolNode)node).Val;
                case ASTNode.ASTNodeType.StringNode:
                    return ((StringNode)node).Val;
                case ASTNode.ASTNodeType.SymbolNode:
                    string symName = ((SymbolNode)node).Val;
                    return EvalNode(context.Find(symName), context);
                case ASTNode.ASTNodeType.ObjectNode:
                    return ((ObjectNode)node).Val;
                case ASTNode.ASTNodeType.NilNode:
                    return null;
                case ASTNode.ASTNodeType.CharacterNode:
                    return ((CharacterNode)node).Val;
                case ASTNode.ASTNodeType.CommentNode:
                    return ((CommentNode)node).Text;
                case ASTNode.ASTNodeType.KeywordNode:
                    return ((KeywordNode)node).Val;
                case ASTNode.ASTNodeType.NumberNode:
                    return ((NumberNode)node).NumberVal;
                case ASTNode.ASTNodeType.VectorNode:
                    ASTNode[] nodes = ((VectorNode)node).nodes;
                    object[] retVec = new object[nodes.Length];
                    for (int i=0;i<nodes.Length;i++)
                    {
                        retVec[i] = EvalNode(nodes[i],context);
                    }
                    return retVec;

            }
            return null;
        }

       public   static void ApplyMacro(ASTNode node,ASTNode parentNode)
        {
            if (Macros != null)
            {
                for (int i = 0; i < Macros.Count; i++)
                {
                    Macros[i](node, parentNode);
                }
            }
            switch (node.NodeType)
            {
                case ASTNode.ASTNodeType.ListNode:
                    ListNode listNode = (ListNode)node;
                    foreach (ASTNode lstNode in listNode.nodes)
                    {
                        ApplyMacro(lstNode, node);
                    }
                break;
                case ASTNode.ASTNodeType.MapNode:
                    MapNode mapNode = (MapNode)node;
                    foreach (DictionaryEntry dic in mapNode.Values)
                    {
                        ApplyMacro((ASTNode)dic.Key, node);
                        ApplyMacro((ASTNode)dic.Value, node);
                    }
                break;
                case ASTNode.ASTNodeType.VectorNode:
                    VectorNode vecNode = (VectorNode)node;
                    for (int i = 0; i < vecNode.nodes.Length; i++)
                    {
                        ApplyMacro(vecNode.nodes[i], node);
                    }
                break;
                case ASTNode.ASTNodeType.QuoteNode:
                    QuoteNode qNode = (QuoteNode)node;
                    ApplyMacro(qNode.Node, node);
                break;
            }
        }

    }


}